package cn.gdchent.springbootsecurity.config;

import cn.gdchent.springbootsecurity.authentication.BackdoorAuthenticationProvider;
import cn.gdchent.springbootsecurity.authentication.JwtAuthenticationTokenFilter;
import cn.gdchent.springbootsecurity.configbean.SecurityUserDetailsServiceBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.BeanIds;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.sql.DataSource;

/**
 * @auther:gdchent
 * @create:2020/4/17 10:19
 * @Description:
 */
@EnableWebSecurity //该注解会被spring发现并注册
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    /**
     * 自定义用户认证逻辑
     */
    @Autowired
    @Qualifier(value = "userDetailsServiceImpl")
    private UserDetailsService userDetailsService;

    @Autowired
    private BackdoorAuthenticationProvider backdoorAuthenticationProvider;

    @Autowired
    private SecurityUserDetailsServiceBean securityUserDetailsServiceBean;

    @Autowired
    private DataSource dataSource;

    @Autowired
    private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
    /**
     * 权限详解剖析
     * https://www.qikegu.com/docs/2570
     *
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        System.out.println("configure授权方法被调用");
        //实用自定义表单登录页
        http.authorizeRequests()//开启配置
                .antMatchers("/", "/index", "/error", "/doLogin", "/register").permitAll() //不需要扽牢固
                .antMatchers("/admin/api/**").hasAuthority("ROLE_ADMIN") //hasRole默认 加了ROLE_这个前缀
                .antMatchers("/user/api/**").hasRole("USER")//hasRole默认 加了ROLE_这个前缀
                .antMatchers("/app/api/**").permitAll() //**所有接口都公开
                .and()
                //.formLogin() //表单登录
                //.loginPage("/login")//当我们配置了 loginPage 为 /login.html 之后，这个配置从字面上理解，就是设置登录页面的地址为 /login.html
                //.loginProcessingUrl("/doLogin") //指定登录请求成功的路径  这个跟successHandler只能选择其中一个
                //.usernameParameter("username") //如果使用前后端分离 这里就不用了  直接走接口 通过jwt方式
                //.passwordParameter("password")  // 如果使用前后端分离 这里就不用了  直接走接口 通过jwt方式
                //.successHandler(securityUserDetailsServiceBean.loginSuccessHandler())
                //.failureForwardUrl("/loginError") //登录失败 如果是由后台控制业务逻辑 情况  二者取其一
                //.failureHandler(securityUserDetailsServiceBean.loginFailureHandler())
                //.permitAll()
                //.and()
                //.logout()
                //.logoutUrl("/logoutUrl")
                //.logoutSuccessUrl("/logoutSuccessUrl")  //logoutSuccessHandler 二者取其一
                //.logoutSuccessHandler(securityUserDetailsServiceBean.logoutSuccessHandler())
                //.permitAll()
                //.and()
                // 基于token，不需要csrf 禁用CSRF
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class)
                .csrf()
                .disable();
                 //当前后端分离的时候 其实就是前端根据后端返回的json字符串 来自己控制业务逻辑
//                .exceptionHandling() //https://m.imooc.com/article/293258?block_id=tuijian_wz
//                .authenticationEntryPoint(new AuthenticationEntryPoint() {
//                    @Override
//                    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
//                        System.out.println("loginxx");
//                        response.setContentType("application/json;charset=UTF-8");
//                        response.setStatus(ResultStatusEnum.UNAUTHORIZED.getStatus()); //当前端接受到这个状态码是 401的时候 接受业务逻辑的处理
//                        PrintWriter printWriter=response.getWriter();
//                        HttpResultMap resultMap=new HttpResultMap();
//                        if(authException instanceof InsufficientAuthenticationException){
//                            resultMap.put(HttpResultMap.CODE_TAG, ResultStatusEnum.UNAUTHORIZED.getStatus());
//                            resultMap.put(HttpResultMap.MSG_TAG, ResultStatusEnum.UNAUTHORIZED.getMsg());
//                        }
//                        JSONObject jsonObject=new JSONObject();
//                        resultMap.put(HttpResultMap.DATA_TAG,jsonObject);
//                        printWriter.write(new ObjectMapper().writeValueAsString(resultMap));
//                    }
//                });
    }

    /**
     * 身份认证接口
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //将自定义验证类注册进去
        //auth.authenticationProvider(backdoorAuthenticationProvider);
        //加入数据库验证类，下面的语句实际上在验证链中加入了一个DaoAuthenticationProvider 登录时密码加密校验
        auth.userDetailsService(userDetailsService).passwordEncoder(securityUserDetailsServiceBean.passwordEncoder());
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/resources/**/*.html", "/resources/**/*.js");
    }

    @Bean(name = BeanIds.AUTHENTICATION_MANAGER)
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
}
